import copy
import enum

import numpy as np
import pandas as pd
import simpy


class Objective:
    # 状态定义：
    # -2. 无任务空闲状态 / 无法作业状态
    # -1. 避让状态
    # 0. 有任务空闲状态
    # 1. 空载移动状态
    # 2. 抓取状态
    # 3. 重载移动状态
    # 4. 放置状态
    # 5. 换线状态
    PRIORITY = [-2, -1, 0, 5, 1, 3, 2, 4]
    SafetyDistance = 1
    # 环境定义
    env = simpy.Environment()
    # 全局事件定义
    SimulationStopEvent = env.event()
    ShaduleEvent = env.event()
    CraneTaskQueue = []
    ReachStackerTaskQueue = []

    # 轨道吊任务队列
    # CraneTaskQueue =[{'StartPosition': [2,7,2], 'EndPosition': [15,7,1]}]
    # ReachStackerTaskQueue =[{'StartPosition': [2,8,1], 'EndPosition': [15,9,1]}]
    def __init__(self):
        ContainerLocationTable = pd.read_excel("箱位状态表(20240325目前可用).xlsx")
        for index, row in ContainerLocationTable.iterrows():
            Objective.ContainerLocation(stack=row["栈位"], bay=row["贝位"], level=row["层位"], state=row["占用状态"],
                                        Locationtype=row["位置类型"])
        self.ContainerLocationCopy = copy.deepcopy(Objective.ContainerLocation.ContainerList)

    def evaluate(self, CraneTaskQueue, ReachStackerTaskQueue):
        Objective.env = simpy.Environment()
        self.ReachStacker = Objective.ReachStacker(Objective.env, "ReachStacker", self)
        self.Crane = Objective.Crane(Objective.env, "Crane", self)
        self.ControllStation = Objective.ControllStation(Objective.env, self)
        Objective.ContainerLocation.ContainerList = copy.deepcopy(self.ContainerLocationCopy)
        Objective.CraneTaskQueue = CraneTaskQueue
        Objective.ReachStackerTaskQueue = ReachStackerTaskQueue
        Objective.SimulationStopEvent = Objective.env.event()
        Objective.ShaduleEvent = Objective.env.event()
        Objective.env.run(Objective.SimulationStopEvent)
        del self.ReachStacker
        del self.Crane
        del self.ControllStation
        return Objective.env.now

    "----------------------------工具函数-----------------------------"

    def Get_MoveRange(*args: list) -> np.ndarray:
        if len(args) == 2:
            Position = args[1]
            return np.arange(Position[0] - Objective.SafetyDistance, Position[0] + 1 + Objective.SafetyDistance)
        if len(args) == 3:
            StartPoint = args[1]
            EndPoint = args[2]
            # 判断起点和终点的位置关系
            if StartPoint[0] == EndPoint[0]:
                return np.arange(StartPoint[0] - Objective.SafetyDistance, EndPoint[0] + 1 + Objective.SafetyDistance)
            elif StartPoint[0] < EndPoint[0]:
                return np.arange(StartPoint[0] - Objective.SafetyDistance, EndPoint[0] + 1 + Objective.SafetyDistance)
            else:
                return np.arange(StartPoint[0] + Objective.SafetyDistance, EndPoint[0] - 1 - Objective.SafetyDistance,
                                 -1)

    # "----------------------------绘图类-----------------------------"
    #
    # class DrawPicture:
    #     ContainerChangeLocationList = []
    #     ContainerChangeLocationTimeList = []
    #
    #     def __init__(self):
    #         self.ani = None
    #         self.DeviceSC = None
    #         self.ContainerSC1 = None
    #         self.ContainerSC2 = None
    #         self.ChangeDict = {}
    #         plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    #         plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    #         self.fig = plt.figure()
    #         self.ax = self.fig.add_subplot(111)
    #         self.text = self.ax.text(0, 14, "时间点: %d" % 0)
    #         self.ax.set_xlim(1, 66)
    #         self.ax.set_ylim(1, 14)
    #         self.xtick = range(0, 66)
    #         self.ytick = range(0, 15)
    #         self.ax.set_xticks(self.xtick)
    #         self.ax.set_yticks(self.ytick)
    #         self.ax.grid(True)
    #         self.ax.set_aspect(1)
    #         self.ax.set_xlabel("贝位")
    #         self.ax.set_ylabel("栈位")
    #         self.ax.set_title("集装箱堆场")
    #         self.Locationlist1 = []
    #         self.Locationlist2 = []
    #         self.StateColor = {-2: 'yellow', -1: 'blue', 0: 'yellow', 1: 'green', 2: 'black', 3: 'red', 4: 'black',
    #                            5: 'aquamarine'}
    #         # self.init_containerlocation()
    #
    #     def LoadData(self, loclist1, loclist2, ContainerLocationInit):
    #         self.ChangeDict = dict(
    #             zip(DrawPicture.ContainerChangeLocationTimeList, DrawPicture.ContainerChangeLocationList))
    #         self.Locationlist1 = loclist1
    #         self.Locationlist2 = loclist2
    #         # 寻找一层集装箱位置
    #         self.ContainerLocationList = ContainerLocationInit
    #         # 创建一个 66*15 的网格
    #         x = np.arange(1, 67)
    #         y = np.arange(1, 15)
    #         X, Y = np.meshgrid(x, y)
    #         # 集装箱散点图一层图层
    #         self.ContainerSC1 = self.ax.scatter([], [], s=100, marker='s', alpha=1, c='orange')
    #         self.ContainerSC2 = self.ax.scatter([], [], s=100, marker='s', alpha=1, c='brown')
    #         # 查找一层现有集装箱位置
    #         index = np.where(ContainerLocationInit[0][:][:] == 1)
    #         indices_to_remove = list(zip(index[0], index[1]))
    #         # 创建布尔索引
    #         mask = np.zeros(X.shape, dtype=bool)
    #         for index in indices_to_remove:
    #             mask[index[0], index[1]] = True
    #         # 应用布尔索引移除值
    #         X_masked = X[mask]
    #         Y_masked = Y[mask]
    #         # 将网格展平为一维数组
    #         x_flattened = X_masked.flatten()
    #         y_flattened = Y_masked.flatten()
    #         self.ContainerSC1.set_offsets(np.c_[x_flattened, y_flattened])
    #         # 查找二层现有集装箱位置
    #         index = np.where(ContainerLocationInit[1][:][:] == 1)
    #         indices_to_remove = list(zip(index[0], index[1]))
    #         # 创建布尔索引
    #         mask = np.zeros(X.shape, dtype=bool)
    #         for index in indices_to_remove:
    #             mask[index[0], index[1]] = True
    #         # 应用布尔索引移除值
    #         X_masked = X[mask]
    #         Y_masked = Y[mask]
    #         # 将网格展平为一维数组
    #         x_flattened = X_masked.flatten()
    #         y_flattened = Y_masked.flatten()
    #         self.ContainerSC2.set_offsets(np.c_[x_flattened, y_flattened])
    #         # 设备散点图图层
    #         self.DeviceSC = self.ax.scatter([], [], s=70, marker='s')
    #         self.ani = FuncAnimation(self.fig, self.update, frames=len(self.Locationlist1) + 1, interval=10, blit=False,
    #                                  repeat=False)  # 创建动画效果
    #
    #     def update(self, frame):
    #         # 时间点提示向左偏移
    #         if self.Locationlist1[frame][3] in self.ChangeDict:
    #             x = np.arange(1, 67)
    #             y = np.arange(1, 15)
    #             X, Y = np.meshgrid(x, y)
    #             # 查找一层现有集装箱位置
    #             index = np.where(self.ChangeDict[self.Locationlist1[frame][3]][0][:][:] == 1)
    #             indices_to_remove = list(zip(index[0], index[1]))
    #             # 创建布尔索引
    #             mask = np.zeros(X.shape, dtype=bool)
    #             for index in indices_to_remove:
    #                 mask[index[0], index[1]] = True
    #             # 应用布尔索引移除值
    #             X_masked = X[mask]
    #             Y_masked = Y[mask]
    #             # 将网格展平为一维数组
    #             x_flattened = X_masked.flatten()
    #             y_flattened = Y_masked.flatten()
    #             self.ContainerSC1.set_offsets(np.c_[x_flattened, y_flattened])
    #             # 查找二层现有集装箱位置
    #             index = np.where(self.ChangeDict[self.Locationlist1[frame][3]][1][:][:] == 1)
    #             indices_to_remove = list(zip(index[0], index[1]))
    #             # 创建布尔索引
    #             mask = np.zeros(X.shape, dtype=bool)
    #             for index in indices_to_remove:
    #                 mask[index[0], index[1]] = True
    #             # 应用布尔索引移除值
    #             X_masked = X[mask]
    #             Y_masked = Y[mask]
    #             # 将网格展平为一维数组
    #             x_flattened = X_masked.flatten()
    #             y_flattened = Y_masked.flatten()
    #             self.ContainerSC2.set_offsets(np.c_[x_flattened, y_flattened])
    #         self.text.set_text("时间点: %d" % self.Locationlist1[frame][3])
    #         x1 = self.Locationlist1[frame][0]
    #         y1 = self.Locationlist1[frame][1]
    #         Point1color = self.StateColor[self.Locationlist1[frame][2]]
    #         Point1color = mcolors.to_rgba(Point1color)
    #         x2 = self.Locationlist2[frame][0]
    #         y2 = self.Locationlist2[frame][1]
    #         Point2color = self.StateColor[self.Locationlist2[frame][2]]
    #         Point2color = mcolors.to_rgba(Point2color)
    #         self.DeviceSC.set_offsets([[x1, y1], [x2, y2]])
    #         self.DeviceSC.set_facecolors([Point1color, Point2color])

    "----------------------------枚举类-----------------------------"

    class WorkLinePos(enum.Enum):
        Up = 1
        Down = 2

    "----------------------------集装箱箱位类-----------------------------"

    class ContainerLocation:
        ContainerList = []
        ContainerListCopy = []

        def __init__(self, bay, stack, level, state, Locationtype):
            self.bay = bay  # 贝位
            self.level = level  # 层位
            self.stack = stack  # 栈位
            self.state = state  # 集装箱箱位状态: 放置货物 1 没有货物 0
            self.Locationtype = Locationtype  # 箱位类型: 0 普通箱位 1 道路箱位
            Objective.ContainerLocation.ContainerList.append(self)

        # 根据箱位号查询箱位对象列表
        @classmethod
        def FindContainerLocation(cls, bay, stack, level):
            return [x for x in cls.ContainerList if (x.stack == stack and x.level == level and x.bay == bay)]

        @classmethod
        def ContainerLocationListSave(cls):
            cls.ContainerListCopy.clear()
            cls.ContainerListCopy = copy.deepcopy(cls.ContainerList)
            return True

        @classmethod
        def ContainerLocationListRecover(cls):
            cls.ContainerList.clear()
            cls.ContainerList = copy.deepcopy(cls.ContainerListCopy)
            return True

        # 判断集装箱位置是否可抓取
        def CheckContainerLocationPick(self):
            # 如果当前货位上有货物，进一步判断
            if self.state == 1:
                # 如果当前货位处于二层，可以抓取
                if self.level == 2:
                    return True
                # 如果当前货位处于一层，判断二层是否有货物
                elif self.level == 1:
                    try:
                        # 获取二层货位对象
                        ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(self.bay,
                                                                                                    self.stack,
                                                                                                    self.level + 1).pop()
                    except IndexError:
                        return True
                    # 如果二层货位上有货物不可抓取，否则可以抓取
                    if ContainerLocationSelect.state == 1:
                        return False
                    else:
                        return True
            # 如果当前货位上没有货物，不可抓取
            else:
                return False

        def CheckContainerLocationPut(self):
            # 如果当前货位上没有货物，进一步判断
            if self.state == 0:
                # 如果当前货位处于一层，可以放置
                if self.level == 1:
                    return True
                # 如果当前货位处于二层，判断一层是否有货物
                elif self.level == 2:
                    # 获取二层货位对象
                    ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(self.bay, self.stack,
                                                                                                self.level - 1).pop()
                    # 如果一层货位上有货物则可以放置，否则不可放置
                    if ContainerLocationSelect.state == 1:
                        return True
                    else:
                        return False
            # 如果当前货位上有货物，不可放置
            else:
                return False

        # 计算正面吊可以停靠的位置
        def DockingLocationSearch(self):
            TargetBay = self.bay
            # 获得目标位置的贝位和栈位
            TargetStack = self.stack
            # 栈位超出范围，无解，给出异常
            assert 3 < TargetStack < 15
            # 通道规则
            if TargetStack == 4:
                return [None, [TargetBay, 5]]
            if TargetStack == 5:
                return [None, [TargetBay, 6]]
            if TargetStack == 6:
                return [None, [TargetBay, 5]]
            if TargetStack == 13:
                return [[TargetBay, 14], None]
            if TargetStack == 14:
                return [[TargetBay, 13], None]
            MovePathUp = []
            MovePathDown = []
            CheckStack = TargetStack
            while True:
                # 向上侧查找，先判断是否为道路,若为道路,则将检查位置加入路径，退出
                CheckStack += 1
                ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                            1).pop()
                if ContainerLocationSelect.Locationtype == 1:
                    MovePathUp.append(CheckStack)
                    break
                # 若不为道路，则检查当前位置一层是否有集装箱，若有则不能成为可用路径
                else:
                    if ContainerLocationSelect.state == 0:
                        MovePathUp.append(CheckStack)
                        continue
                    else:
                        # 判断是否为目标栈位的邻接栈位，若是则检查二层是否有集装箱，若没有则继续搜索，否则直接退出
                        if abs(CheckStack - TargetStack) == 1:
                            if Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                 2).pop().state <= \
                                    Objective.ContainerLocation.FindContainerLocation(TargetBay, TargetStack,
                                                                                      2).pop().state:
                                continue
                            else:
                                MovePathUp.clear()
                                break
                        else:
                            MovePathUp.clear()
                            break
            CheckStack = TargetStack
            while True:
                # 向下侧查找，先判断是否为道路,若为道路,则将检查位置加入路径，退出
                CheckStack -= 1
                ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                            1).pop()
                if ContainerLocationSelect.Locationtype == 1:
                    MovePathDown.append(CheckStack)
                    break
                # 若不为道路，则检查当前位置一层是否有集装箱，若有则不能成为可用路径
                else:
                    if ContainerLocationSelect.state == 0:
                        MovePathDown.append(CheckStack)
                        continue
                    else:
                        # 判断是否为目标栈位的邻接栈位，若是则检查二层是否有集装箱，若没有则继续搜索，否则直接退出
                        if abs(CheckStack - TargetStack) == 1:
                            if Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                 2).pop().state <= \
                                    Objective.ContainerLocation.FindContainerLocation(TargetBay, TargetStack,
                                                                                      2).pop().state:
                                continue
                            else:
                                MovePathDown.clear()
                                break
                        else:
                            MovePathDown.clear()
                            break
            if len(MovePathUp) != 0 or len(MovePathDown) != 0:
                if len(MovePathUp) != 0:
                    MovePathUp = np.array(MovePathUp)
                    DockingLocationUp = [TargetBay, np.min(MovePathUp)]
                else:
                    DockingLocationUp = None
                if len(MovePathDown) != 0:
                    MovePathDown = np.array(MovePathDown)
                    DockingLocationDown = [TargetBay, np.max(MovePathDown)]
                else:
                    DockingLocationDown = None
                return [DockingLocationUp, DockingLocationDown]
            else:
                return False

        def PlacingFeasibilityQueries(self):
            TargetBay = self.bay
            TargetStack = self.stack
            if TargetStack < 7 or TargetStack > 12:
                return True
            else:
                # 初始化集装箱位置列表
                ContainerLocationInit = []
                for stack in range(7, 13):
                    ContainerLocationInit.append(
                        Objective.ContainerLocation.FindContainerLocation(TargetBay, stack, 1).pop())
                # 记录活动集装箱位置（即正面吊所涉及的所有集装箱位置）
                ActiveContainerLocation = []
                for item in Objective.ReachStackerTaskQueue:
                    for key, value in item.items():
                        selectselectContainerLocation = Objective.ContainerLocation.FindContainerLocation(value[0],
                                                                                                          value[1],
                                                                                                          1).pop()
                        if (selectselectContainerLocation.state == 1 and key == "StartPosition") or key == "EndPosition":
                            ActiveContainerLocation.append(
                                Objective.ContainerLocation.FindContainerLocation(value[0], value[1], 1).pop())
                        else:
                            continue
                # 删除活动集装箱位置，剩下的即为固定集装箱位置（即正面吊不涉及的集装箱位置）
                for item in ActiveContainerLocation:
                    try:
                        ContainerLocationInit.remove(item)
                    except ValueError:
                        continue
                FixedContainerPosition = ContainerLocationInit.copy()
                TargetBay = self.bay
                TargetStack = self.stack
                CheckStack = TargetStack
                FixContainerexistFlag = False
                ActiveContainerexistFlag = False
                while True:
                    # 向上侧查找，先判断是否为道路,若为道路,则将检查位置加入路径，退出
                    CheckStack += 1
                    ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                                1).pop()
                    if ContainerLocationSelect.Locationtype == 1:
                        break
                    else:
                        if ContainerLocationSelect in FixedContainerPosition:
                            FixContainerexistFlag = True
                        if ContainerLocationSelect in ActiveContainerLocation:
                            ActiveContainerexistFlag = True
                if FixContainerexistFlag == True and ActiveContainerexistFlag == True:
                    return False
                else:
                    pass
                FixContainerexistFlag = False
                ActiveContainerexistFlag = False
                CheckStack = TargetStack
                while True:
                    # 向下侧查找，先判断是否为道路,若为道路则退出
                    CheckStack -= 1
                    ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                                1).pop()
                    if ContainerLocationSelect.Locationtype == 1:
                        break
                    else:
                        if ContainerLocationSelect in FixedContainerPosition:
                            FixContainerexistFlag = True
                        if ContainerLocationSelect in ActiveContainerLocation:
                            ActiveContainerexistFlag = True
                if FixContainerexistFlag == True and ActiveContainerexistFlag == True:
                    return False
                else:
                    return True

    "----------------------------调度控制器类-----------------------------"

    class ControllStation:
        DataStack = []

        def __init__(self, env, obj):
            self.env = env
            self.env.process(self.main())
            self.env.process(self.running())
            self.ShaduleDevice = []
            self.obj = obj

        def running(self):
            yield Objective.SimulationStopEvent
            return True

        # 作业调度函数
        def Schedule(self, Device):
            """-----------------------------------标志位---------------------------------------"""
            # 优先级标志位
            PriorityFlag = False
            # 作业交叉标志位
            CrossFlag = False
            # 主调度设备可作业标志位
            MainShaduleDeviceWorkFeasibility = True
            """-----------------------------------中间变量--------------------------------------"""
            # 调度数据栈
            ScheduleDataStack = []

            # 指定主调度设备与被调度设备
            MainShaduleDevice = Device
            BeShaduleDevice = self.obj.ReachStacker if Device == self.obj.Crane else self.obj.Crane
            # 获取主调度设备基本作业信息
            MainShaduleDeviceStateCode = MainShaduleDevice.StateCode
            MainShaduleDeviceCurrentPos = MainShaduleDevice.CurrentPos
            MainShaduleDeviceCurrentTask = MainShaduleDevice.CurrentTask
            MainShaduleDeviceTargetPos = MainShaduleDevice.TargetPos
            MainShaduleDevicePriority = Objective.PRIORITY.index(MainShaduleDeviceStateCode)
            # 获取被调度设备基本作业信息
            BeShaduleDeviceStateCode = BeShaduleDevice.StateCode
            BeShaduleDeviceCurrentPos = BeShaduleDevice.CurrentPos
            BeShaduleDeviceCurrentTask = BeShaduleDevice.CurrentTask
            BeShaduleDeviceTargetPos = BeShaduleDevice.TargetPos
            BeShaduleDevicePriority = Objective.PRIORITY.index(BeShaduleDeviceStateCode)

            """----------------------------------------作业可行性判断----------------------------------"""
            # 判断主调度设备是否为正面吊
            if MainShaduleDevice is self.obj.ReachStacker:
                # 判断正面吊作业的作业状态
                if not MainShaduleDevice.LoadOn:
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["StartPosition"]
                    # 判断该位置是否能抓取
                    PickUPContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDevice.TargetPos[0],
                        MainShaduleDevice.TargetPos[1],
                        MainShaduleDevice.TargetPos[2]).pop()
                    # 若该位置不能抓取，等待
                    if not PickUPContainerLocation.CheckContainerLocationPick():
                        # 主调度作业设备不可作业
                        MainShaduleDevice.StateCode = -2
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 主调度作业设备可作业
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True
                else:
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["EndPosition"]
                    # 判断该位置是否能放置
                    PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDevice.TargetPos[0],
                        MainShaduleDevice.TargetPos[1],
                        MainShaduleDevice.TargetPos[2]).pop()
                    # 若该位置不能放置，等待
                    if not PutContainerLocation.CheckContainerLocationPut():
                        # 主调度作业设备不可作业
                        MainShaduleDevice.StateCode = -2
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 主调度作业设备可作业
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True
                # 获得正面吊的停靠位置
                DockingLocation = Objective.ContainerLocation.FindContainerLocation(MainShaduleDevice.TargetPos[0],
                                                                                    MainShaduleDevice.TargetPos[1],
                                                                                    MainShaduleDevice.TargetPos[
                                                                                        2]).pop().DockingLocationSearch()
                # 无停靠位置，等待or避让
                if DockingLocation is False:
                    # 主调度作业设备不可作业
                    MainShaduleDevice.StateCode = -2
                    MainShaduleDeviceWorkFeasibility = False
                else:
                    # 主调度作业设备可作业
                    MainShaduleDevice.StateCode = 0
                    MainShaduleDeviceWorkFeasibility = True

                # 有停靠位置
                if MainShaduleDevice.Worklinepos == Objective.WorkLinePos.Down and DockingLocation is not False:
                    DockingLocation_ = DockingLocation[1]
                    if DockingLocation_ is None:
                        Objective.ControllStation.DataStack.append(DockingLocation[0])
                        MainShaduleDevice.ReplaceWorkLineEvent.succeed()
                        MainShaduleDevice.ReplaceWorkLineEvent = MainShaduleDevice.env.event()
                        return True
                    else:
                        MainShaduleDevice.TargetPos = DockingLocation_
                        MainShaduleDeviceTargetPos = DockingLocation_

                elif MainShaduleDevice.Worklinepos == Objective.WorkLinePos.Up and DockingLocation is not False:
                    DockingLocation_ = DockingLocation[0]
                    if DockingLocation_ is None:
                        Objective.ControllStation.DataStack.append(DockingLocation[1])
                        MainShaduleDevice.ReplaceWorkLineEvent.succeed()
                        MainShaduleDevice.ReplaceWorkLineEvent = MainShaduleDevice.env.event()
                        return True
                    else:
                        MainShaduleDevice.TargetPos = DockingLocation_
                        MainShaduleDeviceTargetPos = DockingLocation_
            # 判断主调度设备是否为轨道吊
            else:
                # 轨道吊是否处于空载作业状态
                if not MainShaduleDevice.LoadOn:
                    MainShaduleDeviceTargetPos = MainShaduleDevice.CurrentTask["StartPosition"]
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["StartPosition"]
                    # 判断该位置是否能抓取
                    PickUPContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDeviceTargetPos[0],
                        MainShaduleDeviceTargetPos[1],
                        MainShaduleDeviceTargetPos[
                            2]).pop()
                    # 若该位置不能抓取，等待
                    if not PickUPContainerLocation.CheckContainerLocationPick():
                        # 将主调度设备调度状态改为避让状态
                        MainShaduleDevice.StateCode = -2
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 恢复主调度设备作业状态
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True

                else:
                    MainShaduleDeviceTargetPos = MainShaduleDevice.CurrentTask["EndPosition"]
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["EndPosition"]
                    # 判断该位置是否能放置
                    PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDeviceTargetPos[0],
                        MainShaduleDeviceTargetPos[1],
                        MainShaduleDeviceTargetPos[2]).pop()

                    if not PutContainerLocation.PlacingFeasibilityQueries() or not PutContainerLocation.CheckContainerLocationPut():
                        # 将主调度设备调度状态改为避让状态
                        MainShaduleDevice.StateCode = -2
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 恢复主调度设备作业状态
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True
            # 获取主调度设备的预计作业区间
            MainShaduleDeviceMoveRange = None
            if MainShaduleDevice.StateCode == 0:
                MainShaduleDeviceMoveRange = Objective.Get_MoveRange(MainShaduleDevice.CurrentPos,
                                                                     MainShaduleDevice.TargetPos)
            elif MainShaduleDevice.StateCode == -1:
                MainShaduleDeviceMoveRange = Objective.Get_MoveRange(MainShaduleDevice.CurrentPos,
                                                                     MainShaduleDevice.AvoidancePos)
            elif MainShaduleDevice.StateCode == -2:
                MainShaduleDeviceMoveRange = Objective.Get_MoveRange(MainShaduleDevice.CurrentPos)
            # 获取被调度设备的正在作业区间
            BeShaduleDeviceMoveRange = None
            if BeShaduleDevice.StateCode == 0 or BeShaduleDevice.StateCode == 1 or BeShaduleDevice.StateCode == 3 \
                    or BeShaduleDevice.StateCode == 5:
                BeShaduleDeviceMoveRange = Objective.Get_MoveRange(BeShaduleDevice.CurrentPos,
                                                                   BeShaduleDevice.TargetPos)
            elif BeShaduleDevice.StateCode == 2 or BeShaduleDevice.StateCode == 4 or BeShaduleDevice.StateCode == -2:
                BeShaduleDeviceMoveRange = Objective.Get_MoveRange(BeShaduleDevice.CurrentPos)
            elif BeShaduleDeviceStateCode == -1:
                BeShaduleDeviceMoveRange = Objective.Get_MoveRange(BeShaduleDevice.CurrentPos,
                                                                   BeShaduleDevice.AvoidancePos)
            min_val = 0
            max_val = 65
            # 判断主调度设备作业优先级是否大于被调度设备
            if MainShaduleDevice.StateCode == 0 and MainShaduleDevice.LoadOn == True:
                # 获得当前贝位与目标贝位的距离差并归一化
                Distance = abs(MainShaduleDevice.CurrentPos[0] - MainShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                MainShaduleDevicePriority = Objective.PRIORITY.index(MainShaduleDevice.StateCode) + 0.5 + alpha
            else:
                Distance = abs(MainShaduleDevice.CurrentPos[0] - MainShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                MainShaduleDevicePriority = Objective.PRIORITY.index(MainShaduleDevice.StateCode) + alpha
            if BeShaduleDevice.StateCode == 0 and BeShaduleDevice.LoadOn == True:
                Distance = abs(BeShaduleDevice.CurrentPos[0] - BeShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                BeShaduleDevicePriority = Objective.PRIORITY.index(BeShaduleDevice.StateCode) + 0.5 + alpha
            else:
                Distance = abs(BeShaduleDevice.CurrentPos[0] - BeShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                BeShaduleDevicePriority = Objective.PRIORITY.index(BeShaduleDevice.StateCode) + alpha
            if MainShaduleDevicePriority > BeShaduleDevicePriority:
                PriorityFlag = True
            elif MainShaduleDevicePriority == BeShaduleDevicePriority and MainShaduleDevice == self.obj.Crane:
                PriorityFlag = True
            else:
                PriorityFlag = False
            # 判断主调度设备与被调度设备是否交叉
            if self.obj.ReachStacker.Worklinepos == Objective.WorkLinePos.Down and len(
                    np.intersect1d(MainShaduleDeviceMoveRange, BeShaduleDeviceMoveRange)) > 1:
                CrossFlag = True
            else:
                CrossFlag = False

            """---------------------------------------执行作业-------------------------------------------------------"""
            # if MainShaduleDeviceWorkFeasibility is False:
            #     MainShaduleDevice.WaitEvent.succeed()
            #     return True
            # 主调度设备优先级高且两设备不存在路径重叠情形，主调度设备直接作业
            if PriorityFlag == True and CrossFlag == False:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
            # 主调度设备优先级低且两设备不存在路径重叠情形，主调度设备直接作业
            if PriorityFlag == False and CrossFlag == False and MainShaduleDeviceWorkFeasibility is True:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
            if PriorityFlag == False and CrossFlag == False and MainShaduleDeviceWorkFeasibility is False:
                MainShaduleDevice.WaitEvent.succeed()
                MainShaduleDevice.WaitEvent = Objective.env.event()
            # 主调度设备优先级高且两设备存在路径重叠情形，被调度设备作业中断且进行避让，主调度设备优先作业
            if PriorityFlag == True and CrossFlag == True and BeShaduleDevice.DeviceLock == True:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
            elif PriorityFlag == True and CrossFlag == True and BeShaduleDevice.DeviceLock == False:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
                # 判断被动调度设备是否需要避让，即被动调度设备当前位置是否在主调度设备的预计作业区间内
                if BeShaduleDevice.CurrentPos[0] in MainShaduleDeviceMoveRange:
                    if BeShaduleDevice == self.obj.Crane:
                        Avoidanceloc = [np.max(MainShaduleDeviceMoveRange) + 1, BeShaduleDevice.CurrentPos[1]]
                    else:
                        Avoidanceloc = [np.min(MainShaduleDeviceMoveRange) - 1, BeShaduleDevice.CurrentPos[1]]
                    Objective.ControllStation.Avoidance(BeShaduleDevice, Avoidanceloc)
                else:
                    Objective.ControllStation.Wait(BeShaduleDevice)

            # 主调度设备优先级低且两设备存在路径重叠情形，判断主调度设备是否碍事，若碍事则避让，否则原地等待
            if PriorityFlag == False and CrossFlag == True and MainShaduleDevice.DeviceLock == True:
                pass
            elif PriorityFlag == False and CrossFlag == True and MainShaduleDevice.DeviceLock == False:
                CrossRange = np.intersect1d(MainShaduleDeviceMoveRange, BeShaduleDeviceMoveRange)
                if MainShaduleDevice.CurrentPos[0] in CrossRange:
                    if MainShaduleDevice == self.obj.Crane:
                        Avoidanceloc = [np.max(BeShaduleDeviceMoveRange) + 1, MainShaduleDevice.CurrentPos[1]]
                    else:
                        Avoidanceloc = [np.min(BeShaduleDeviceMoveRange) - 1, MainShaduleDevice.CurrentPos[1]]
                    Objective.ControllStation.Avoidance(MainShaduleDevice, Avoidanceloc)
                else:
                    Objective.ControllStation.Wait(MainShaduleDevice)

        @staticmethod
        def Avoidance(obj, loc):
            "避让作业"
            obj.InterruptWorkEvent.succeed()
            obj.InterruptWorkEvent = Objective.env.event()
            # 避让到指定位置
            obj.AvoidancePos = loc
            obj.AvoidanceEvent.succeed()
            obj.AvoidanceEvent = Objective.env.event()
            obj.DeviceLock = True
            return True

        @staticmethod
        def Wait(obj):
            "等待作业"
            obj.InterruptWorkEvent.succeed()
            obj.InterruptWorkEvent = Objective.env.event()
            obj.WaitEvent.succeed()
            obj.WaitEvent = Objective.env.event()
            obj.DeviceLock = True
            return True

        def main(self):
            CraneShaduleCount = 1
            ReachStackerShaduleCount = 1
            while True:
                "----------------------------任务分配-----------------------------"
                # 获取轨道吊相关信息
                CraneInfo = self.obj.Crane.GetInfo("Crane")
                # 获取正面吊相关信息
                ReachStackerInfo = self.obj.ReachStacker.GetInfo("ReachStacker")
                if CraneInfo["CurrentTask"] == {} and Objective.CraneTaskQueue != [] and CraneInfo["StateCode"] == -2:
                    # Crane.CurrentTask = CraneTaskQueue.pop(0)
                    self.obj.Crane.CurrentTask = Objective.CraneTaskQueue[0]
                    self.obj.Crane.StateCode = 0
                    CraneShaduleCount += 1
                    self.ShaduleDevice.append(self.obj.Crane)
                elif CraneInfo["CurrentTask"] == {} and Objective.CraneTaskQueue == []:
                    self.obj.Crane.StateCode = -2
                if ReachStackerInfo["CurrentTask"] == {} and Objective.ReachStackerTaskQueue != [] and ReachStackerInfo[
                    "StateCode"] == -2:
                    # ReachStacker.CurrentTask = ReachStackerTaskQueue.pop(0)
                    self.obj.ReachStacker.CurrentTask = Objective.ReachStackerTaskQueue[0]
                    self.obj.ReachStacker.StateCode = 0
                    ReachStackerShaduleCount += 1
                    self.ShaduleDevice.append(self.obj.ReachStacker)
                elif ReachStackerInfo["CurrentTask"] == {} and Objective.ReachStackerTaskQueue == []:
                    self.obj.ReachStacker.StateCode = -2
                for Device in self.ShaduleDevice:
                    self.Schedule(Device)
                    print("{}调度，当前设备状态为{}".format(Device.name, Device.StateCode))
                self.ShaduleDevice.clear()
                "----------------------------仿真结束条件-----------------------------"
                # 获取轨道吊相关信息
                CraneInfo = self.obj.Crane.GetInfo("Crane")
                # 获取正面吊相关信息
                ReachStackerInfo = self.obj.ReachStacker.GetInfo("ReachStacker")
                if Objective.CraneTaskQueue == [] and Objective.ReachStackerTaskQueue == [] and CraneInfo[
                    "CurrentTask"] == {} and \
                        ReachStackerInfo["CurrentTask"] == {}:
                    Objective.SimulationStopEvent.succeed()
                    break
                else:
                    yield Objective.ShaduleEvent
                    Device = Objective.ShaduleEvent.value
                    if Device.CurrentTask != {}:
                        self.ShaduleDevice.append(Objective.ShaduleEvent.value)
                    Objective.ShaduleEvent = Objective.env.event()

    "----------------------------正面吊类-----------------------------"

    class ReachStacker(simpy.Resource):
        ReachtSackerName = dict()

        def __init__(self, env, name, obj):
            super().__init__(env)
            self.name = name
            self.env = env
            self.CurrentTask = {}  # 记录当前作业的任务
            self.CurrentPos = [0, 6]  # 记录正面吊当前位置
            self.AvoidancePos = []  # 记录避让位置
            self.StateCode = -2
            self.GANTRY_SPEED = 3  # 移动一个贝位所需要的时间
            self.TROLLEY_SPEED = 3  # 移动一个栈位所需要的时间
            self.PICK_TIME = 50
            self.PUT_TIME = 50
            self.Safe_Distance = Objective.SafetyDistance  # 安全距离
            self.TargetPos = [0, 6]
            self.EnterPos = []
            self.InterruptFlag = False
            self.PosRegister = []  # 记录正面吊大车位置
            self.Worklinepos = Objective.WorkLinePos.Down
            self.DataStack = []
            self.obj = obj
            Objective.ReachStacker.ReachtSackerName[self.name] = self

            "----------------------------标志位定义-----------------------------"
            self.GantryMoveingFlag = False
            self.TrolleyMoveingFlag = False
            self.DeviceLock = False  # 设备锁
            self.LoadOn = False  # 负载状态

            "----------------------------事件定义-----------------------------"
            self.GantryMoveEvent = self.env.event()  # 大车开始移动事件
            self.GantryMoveOverEvent = self.env.event()  # 大车移动结束事件
            self.TrolleyMoveEvent = self.env.event()  # 小车开始移动事件
            self.TrolleyMoveOverEvent = self.env.event()  # 小车移动结束事件
            self.MoveEvent = self.env.event()  # 开始移动事件
            self.PickEvent = self.env.event()  # 抓取事件
            self.PutEvent = self.env.event()  # 放置事件
            self.AvoidanceEvent = self.env.event()  # 避让事件
            self.AvoidanceOverEvent = self.env.event()  # 避让完成事件
            self.WaitEvent = self.env.event()  # 等待事件
            self.ReplaceWorkLineEvent = self.env.event()  # 更换作业线事件
            self.ReplaceWorkLineOverEvent = self.env.event()  # 更换作业线完成事件
            self.InterruptWorkEvent = self.env.event()
            self.GantryMoveProcessInterruptOver = self.env.event()
            self.TrolleyMoveProcessInterruptOver = self.env.event()

            "----------------------------进程定义-----------------------------"
            self.GantryMoveProcess = self.env.process(self.GantryMove())
            self.TrolleyMoveProcess = self.env.process(self.TrolleyMove())
            self.env.process(self.Move())
            self.env.process(self.Pick())
            self.env.process(self.Put())
            self.env.process(self.AvoidanceMove())
            self.env.process(self.Wait())
            self.env.process(self.LocationRecord())
            self.env.process(self.ReplaceWorkLine())
            self.env.process(self.InterruptWork())

        def LocationRecord(self):
            "记录位置"
            while True:
                yield self.env.timeout(1)
                self.PosRegister.append([self.CurrentPos[0], self.CurrentPos[1], self.StateCode, self.env.now])
                if Objective.SimulationStopEvent.processed:
                    break

        @classmethod
        def GetInfo(cls, name):
            reachtSacker = cls.ReachtSackerName[name]
            infodict = dict()
            infodict['StateCode'] = reachtSacker.StateCode
            infodict['CurrentPos'] = reachtSacker.CurrentPos
            infodict['CurrentTask'] = reachtSacker.CurrentTask
            return infodict

        def AvoidanceMove(self):
            while True:
                yield self.AvoidanceEvent
                self.AvoidanceEvent = self.env.event()  # 避让事件重置
                # 保留当前作业状态
                StateCode = self.StateCode
                # 将作业状态设为-1，表示避让
                self.StateCode = -1
                self.TargetPos = self.AvoidancePos
                self.GantryMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                self.TrolleyMoveEvent.succeed()
                self.TrolleyMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                # 将作业状态设为有任务空闲状态
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

        def ReplaceWorkLine(self):
            while True:
                yield self.ReplaceWorkLineEvent
                self.ReplaceWorkLineEvent = self.env.event()
                # 将作业状态设为5，表示换线
                self.StateCode = 5
                if self.CurrentPos[1] == 5 or self.CurrentPos[1] == 6:
                    self.TargetPos = [0, 14]
                elif self.CurrentPos[1] == 13 or self.CurrentPos[1] == 14:
                    self.TargetPos = [0, 5]
                self.GantryMoveEvent.succeed()
                yield self.GantryMoveOverEvent
                self.TrolleyMoveEvent.succeed()
                yield self.TrolleyMoveOverEvent
                self.Worklinepos = Objective.WorkLinePos.Down if self.Worklinepos == Objective.WorkLinePos.Up else Objective.WorkLinePos.Up
                self.ReplaceWorkLineOverEvent.succeed()
                self.ReplaceWorkLineOverEvent = self.env.event()
                self.TargetPos = Objective.ControllStation.DataStack.pop()
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def InterruptWork(self):
            while True:
                yield self.InterruptWorkEvent
                if self.GantryMoveingFlag:
                    self.GantryMoveProcess.interrupt()
                    yield self.GantryMoveProcessInterruptOver
                    self.GantryMoveProcessInterruptOver = self.env.event()
                if self.TrolleyMoveingFlag:
                    self.TrolleyMoveProcess.interrupt()
                    yield self.TrolleyMoveProcessInterruptOver
                    self.TrolleyMoveProcessInterruptOver = self.env.event()

        def Move(self):
            while True:
                # 抛出开始移动事件，等待事件触发
                yield self.MoveEvent
                # 移动开始事件触发
                # 移动开始事件复位
                self.MoveEvent = self.env.event()
                # 判断当前作业状态，如果作业状态为等待调度状态且没有装载货物，进入下面程序块
                if self.StateCode == 0 and self.LoadOn == False:
                    # 将作业状态设为1，表示正在空载移动
                    self.StateCode = 1
                    # 大车移动开始事件触发
                    self.GantryMoveEvent.succeed()
                    # 大车移动开始事件复位
                    self.GantryMoveEvent = self.env.event()
                    # 等待大车移动结束事件触发
                    yield self.GantryMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        continue
                    # 记录进入通道的位置
                    self.EnterPos = copy.deepcopy(self.CurrentPos)
                    # 小车移动开始事件触发
                    self.TrolleyMoveEvent.succeed()
                    # 小车移动开始事件复位
                    self.TrolleyMoveEvent = self.env.event()
                    # 等待小车移动结束事件触发
                    yield self.TrolleyMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        continue
                    # 抓取事件触发
                    self.PickEvent.succeed()
                    # 抓取事件复位
                    self.PickEvent = self.env.event()

                # 判断当前作业状态，如果作业状态为等待调度状态且装载货物，进入下面程序块
                if self.StateCode == 0 and self.LoadOn == True:
                    # 将作业状态设为3，表示正在重载移动
                    self.StateCode = 3
                    # 大车移动开始事件触发
                    self.GantryMoveEvent.succeed()
                    # 大车移动开始事件复位
                    self.GantryMoveEvent = self.env.event()
                    # 等待大车移动结束事件触发
                    yield self.GantryMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    # 记录进入通道的栈位
                    self.EnterPos = copy.deepcopy(self.CurrentPos)
                    # 小车移动开始事件触发
                    self.TrolleyMoveEvent.succeed()
                    # 小车移动开始事件复位
                    self.TrolleyMoveEvent = self.env.event()
                    # 等待小车移动结束事件触发
                    yield self.TrolleyMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    # 放置事件触发
                    self.PutEvent.succeed()
                    # 放置事件复位
                    self.PutEvent = self.env.event()

        def GantryMove(self):
            while True:
                # 抛出大车移动就绪事件，等待事件触发
                yield self.GantryMoveEvent
                # 大车移动就绪事件复位
                self.GantryMoveEvent = self.env.event()
                while True:
                    self.GantryMoveingFlag = True
                    if self.CurrentPos[0] == self.TargetPos[0]:
                        break
                    else:
                        if self.CurrentPos[0] < self.TargetPos[0]:
                            # 获取轨道吊当前位置
                            CranePos = self.obj.Crane.CurrentPos
                            # 判断安全距离内是否有轨道吊，若是则原地等待，否则移动一个贝位
                            while True:
                                if CranePos[0] == self.CurrentPos[
                                    0] + self.Safe_Distance and self.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            # 移动
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] += 1
                            print("正面吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            print("当前时间为{}".format(self.env.now))
                        else:
                            # 获取轨道吊当前位置
                            CranePos = self.obj.Crane.CurrentPos
                            # 判断安全距离内是否有轨道吊，若是则原地等待，否则移动一个贝位
                            while True:
                                if CranePos[0] == self.CurrentPos[
                                    0] - self.Safe_Distance and self.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] -= 1
                            print("正面吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            print("当前时间为{}".format(self.env.now))
                self.GantryMoveingFlag = False
                self.GantryMoveOverEvent.succeed()
                self.GantryMoveOverEvent = self.env.event()

        def TrolleyMove(self):
            while True:
                # 抛出小车移动就绪事件，等待事件触发
                yield self.TrolleyMoveEvent
                self.TrolleyMoveEvent = self.env.event()
                while True:
                    self.TrolleyMoveingFlag = True
                    if self.CurrentPos[1] == self.TargetPos[1]:
                        break
                    else:
                        if self.CurrentPos[1] < self.TargetPos[1]:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] += 1
                            print("正面吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            print("当前时间为{}".format(self.env.now))
                        else:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] -= 1
                            print("正面吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            print("当前时间为{}".format(self.env.now))
                self.TrolleyMoveingFlag = False
                self.TrolleyMoveOverEvent.succeed()
                self.TrolleyMoveOverEvent = self.env.event()

        def Pick(self):
            while True:
                # 抛出抓取作业事件，等待事件触发
                yield self.PickEvent
                # 抓取作业事件触发
                PickUpContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['StartPosition'][0],
                    self.CurrentTask['StartPosition'][1],
                    self.CurrentTask['StartPosition'][
                        2]).pop()
                # 进入抓取集装箱状态
                self.StateCode = 2
                # 模拟抓取时间
                yield self.env.timeout(self.PICK_TIME)
                # 进入运输集装箱状态
                self.LoadOn = True
                # 集装箱箱位状态改变
                PickUpContainerLocation.state = 0
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in Objective.ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                self.StateCode = 3
                # 返回通道入口
                self.TargetPos = self.EnterPos
                self.GantryMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent
                self.TrolleyMoveEvent.succeed()
                self.TrolleyMoveEvent = self.env.event()
                yield self.TrolleyMoveOverEvent
                # 重置进入通道位置
                self.EnterPos = []
                # 进入等待调度状态
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Put(self):
            while True:
                yield self.PutEvent
                PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['EndPosition'][0],
                    self.CurrentTask['EndPosition'][1],
                    self.CurrentTask['EndPosition'][2]).pop()
                # 进入放置集装箱状态
                self.StateCode = 4
                # 模拟放置时间
                yield self.env.timeout(self.PUT_TIME)
                # 放置集装箱
                self.LoadOn = False
                # 集装箱箱位状态改变
                PutContainerLocation.state = 1
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in Objective.ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                self.StateCode = 1
                # 返回通道入口
                self.TargetPos = self.EnterPos
                self.GantryMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent
                self.TrolleyMoveEvent.succeed()
                self.TrolleyMoveEvent = self.env.event()
                yield self.TrolleyMoveOverEvent
                self.EnterPos = []
                # 进入空闲状态
                self.StateCode = -2
                # 任务完成，清空任务
                self.CurrentTask.clear()
                self.TargetPos = self.CurrentPos
                Objective.ReachStackerTaskQueue.pop(0)
                # 下一次调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Wait(self):
            while True:
                yield self.WaitEvent
                # 重置等待事件
                self.WaitEvent = self.env.event()
                self.StateCode = 0
                # 进入等待状态
                yield self.env.timeout(5)
                # 等待调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

    "----------------------------轨道吊类-----------------------------"

    class Crane(simpy.Resource):
        CraneName = dict()

        def __init__(self, env, name, obj):
            super().__init__(env)
            self.obj = obj
            self.name = name
            self.env = env
            self.CurrentTask = {}  # 记录轨道吊当前任务
            self.CurrentPos = [18, 0]  # 记录轨道吊当前位置
            self.AvoidancePos = []  # 记录轨道吊避让位置
            self.StateCode = -2
            self.GANTRY_SPEED = 8  # 移动一个贝位所需要的时间
            self.TROLLEY_SPEED = 6  # 移动一个栈位所需要的时间
            self.PICK_TIME = 50  # 抓取集装箱的所需时间
            self.PUT_TIME = 50  # 放置集装箱的所需时间
            self.Safe_Distance = Objective.SafetyDistance  # 安全距离
            self.TargetPos = [18, 0]  # 移动目标位置
            self.PosRegister = []  # 记录轨道吊大车位置
            Objective.Crane.CraneName[self.name] = self

            # 标志位定义
            self.GantryMoveingFlag = False  # 大车正在移动标志位
            self.TrolleyMoveingFlag = False  # 小车正在移动标志位
            self.InterruptFlag = False  # 中断标志位
            self.DeviceLock = False  # 设备锁
            self.LoadOn = False  # 负载状态

            # 事件定义
            self.GantryMoveEvent = self.env.event()  # 大车开始移动事件
            self.GantryMoveOverEvent = self.env.event()  # 大车移动结束事件
            self.TrolleyMoveEvent = self.env.event()  # 小车开始移动事件
            self.TrolleyMoveOverEvent = self.env.event()  # 小车移动结束事件
            self.MoveEvent = self.env.event()  # 移动事件
            self.PickEvent = self.env.event()  # 抓取事件
            self.PutEvent = self.env.event()  # 放置事件
            self.AvoidanceEvent = self.env.event()  # 避让事件
            self.AvoidanceOverEvent = self.env.event()  # 避让完成事件
            self.WaitEvent = self.env.event()  # 等待事件
            self.InterruptWorkEvent = self.env.event()
            self.GantryMoveProcessInterruptOver = self.env.event()
            self.TrolleyMoveProcessInterruptOver = self.env.event()

            # 进程定义
            self.GantryMoveProcess = self.env.process(self.GantryMove())
            self.TrolleyMoveProcess = self.env.process(self.TrolleyMove())
            self.env.process(self.Move())
            self.env.process(self.Pick())
            self.env.process(self.Put())
            self.env.process(self.AvoidanceMove())
            self.env.process(self.Wait())
            self.env.process(self.LocationRecord())
            self.env.process(self.InterruptWork())

        def LocationRecord(self):
            "记录轨道吊位置"
            while True:
                yield self.env.timeout(1)
                self.PosRegister.append([self.CurrentPos[0], self.CurrentPos[1], self.StateCode, self.env.now])
                if Objective.SimulationStopEvent.processed:
                    break

        @classmethod
        def GetInfo(cls, name):
            reachtSacker = cls.CraneName[name]
            infodict = dict()
            infodict['StateCode'] = reachtSacker.StateCode
            infodict['CurrentPos'] = reachtSacker.CurrentPos
            infodict['CurrentTask'] = reachtSacker.CurrentTask
            infodict['TargetPos'] = reachtSacker.TargetPos
            return infodict

        def Move(self):
            while True:
                yield self.MoveEvent
                self.MoveEvent = self.env.event()
                if self.StateCode == 0 and self.LoadOn == False:
                    self.TargetPos = self.CurrentTask['StartPosition']
                    self.StateCode = 1
                    self.GantryMoveEvent.succeed()
                    self.TrolleyMoveEvent.succeed()
                    self.GantryMoveEvent = self.env.event()
                    self.TrolleyMoveEvent = self.env.event()
                    yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    self.PickEvent.succeed()

                if self.StateCode == 0 and self.LoadOn == True:
                    self.TargetPos = self.CurrentTask['EndPosition']
                    self.StateCode = 3
                    self.GantryMoveEvent.succeed()
                    self.TrolleyMoveEvent.succeed()
                    self.GantryMoveEvent = self.env.event()
                    self.TrolleyMoveEvent = self.env.event()
                    yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    self.PutEvent.succeed()

        def AvoidanceMove(self):
            while True:
                yield self.AvoidanceEvent
                self.AvoidanceEvent = self.env.event()
                # 将作业状态设为-1，表示避让
                self.StateCode = -1
                self.TargetPos = self.AvoidancePos
                self.GantryMoveEvent.succeed()
                self.TrolleyMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                self.TrolleyMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                self.InterruptFlag = False
                # 将作业状态设为有任务空闲状态
                self.StateCode = 0
                # 避让完成,进行下次调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

        def GantryMove(self):
            while True:
                yield self.GantryMoveEvent
                self.GantryMoveEvent = self.env.event()
                while True:
                    self.GantryMoveingFlag = True
                    if self.CurrentPos[0] == self.TargetPos[0]:
                        break
                    else:
                        if self.CurrentPos[0] < self.TargetPos[0]:
                            ReachStackerPos = self.obj.ReachStacker.CurrentPos
                            while True:
                                if ReachStackerPos[0] == self.CurrentPos[
                                    0] + self.Safe_Distance and self.obj.ReachStacker.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] += 1
                            print("轨道吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            print("当前时间为{}".format(self.env.now))
                        else:
                            ReachStackerPos = self.obj.ReachStacker.CurrentPos
                            while True:
                                if ReachStackerPos[0] == self.CurrentPos[
                                    0] - self.Safe_Distance and self.obj.ReachStacker.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] -= 1
                            print("轨道吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            print("当前时间为{}".format(self.env.now))
                self.GantryMoveingFlag = False
                self.GantryMoveOverEvent.succeed()
                self.GantryMoveOverEvent = self.env.event()

        def TrolleyMove(self):
            while True:
                yield self.TrolleyMoveEvent
                self.TrolleyMoveEvent = self.env.event()
                while True:
                    self.TrolleyMoveingFlag = True
                    if self.CurrentPos[1] == self.TargetPos[1]:
                        break
                    else:
                        if self.CurrentPos[1] < self.TargetPos[1]:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] += 1
                            print("轨道吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            print("当前时间为{}".format(self.env.now))
                        else:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] -= 1
                            print("轨道吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            print("当前时间为{}".format(self.env.now))
                self.TrolleyMoveingFlag = False
                self.TrolleyMoveOverEvent.succeed()
                self.TrolleyMoveOverEvent = self.env.event()

        def Pick(self):
            while True:
                yield self.PickEvent
                self.PickEvent = self.env.event()
                # 进入抓取集装箱状态
                self.StateCode = 2
                # 模拟抓取时间
                yield self.env.timeout(self.PICK_TIME)
                self.LoadOn = True
                # 箱位状态调整
                PickContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['StartPosition'][0],
                    self.CurrentTask['StartPosition'][1],
                    self.CurrentTask['StartPosition'][
                        2]).pop()
                PickContainerLocation.state = 0
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in Objective.ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Put(self):
            while True:
                yield self.PutEvent
                self.PutEvent = self.env.event()
                # 进入放置集装箱状态
                self.StateCode = 4
                # 模拟放置时间
                yield self.env.timeout(self.PUT_TIME)
                self.LoadOn = False
                PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['EndPosition'][0],
                    self.CurrentTask['EndPosition'][1],
                    self.CurrentTask['EndPosition'][2]).pop()
                PutContainerLocation.state = 1
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                # 进入空闲状态
                self.StateCode = -2
                self.PutEvent = self.env.event()
                # 任务完成，清空任务
                self.CurrentTask.clear()
                self.TargetPos = self.CurrentPos
                Objective.CraneTaskQueue.pop(0)
                # 下一次调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Wait(self):
            while True:
                yield self.WaitEvent
                self.WaitEvent = self.env.event()
                self.StateCode = 0
                # 进入等待状态
                yield self.env.timeout(5)
                # 重置等待事件
                # 等待调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

        def InterruptWork(self):
            while True:
                yield self.InterruptWorkEvent
                if self.GantryMoveingFlag:
                    self.GantryMoveProcess.interrupt()
                    yield self.GantryMoveProcessInterruptOver
                    self.GantryMoveProcessInterruptOver = self.env.event()
                if self.TrolleyMoveingFlag:
                    self.TrolleyMoveProcess.interrupt()
                    yield self.TrolleyMoveProcessInterruptOver
                    self.TrolleyMoveProcessInterruptOver = self.env.event()


if __name__ == "__main__":
    CraneTaskQueue = [{'StartPosition': [46, 10, 1], 'EndPosition': [64, 1, 1]}, {'StartPosition': [47, 4, 1], 'EndPosition': [65, 2, 1]}, {'StartPosition': [21, 8, 1], 'EndPosition': [57, 9, 2]}]
    ReachStackerTaskQueue = [{'StartPosition': [7, 10, 2], 'EndPosition': [16, 13, 1]}, {'StartPosition': [58, 8, 2], 'EndPosition': [43, 6, 1]}]
    Objective = Objective()
    print(Objective.evaluate(copy.deepcopy(CraneTaskQueue), copy.deepcopy(ReachStackerTaskQueue)))
